package gormdb

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	Log "github.com/cihub/seelog"

	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// 数据源信息
type DataSourceInfo struct {
	Type        string `json:"type"`
	Name        string `json:"name"`
	User        string `json:"user"`
	Pass        string `json:"pass"`
	Ip          string `json:"ip"`
	Port        string `json:"port"`
	DbName      string `json:"dbName"`
	PrintSql    bool   `json:"printSql"`
	AutoMigrate bool   `json:"autoMigrate"` //是否开启AutoMigrate功能(会创建表、缺失的外键、约束、列和索引)
	PassKey     string `json:"passKey"`     //加密密钥
}

/**
 * 创建数据库连接
 */
func NewDb(dataSourceInfo DataSourceInfo, dbOpenFun func(dsn string) gorm.Dialector) (bool, string, interface{}) {
	dbConfig := &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: !dataSourceInfo.AutoMigrate,
	}

	if dataSourceInfo.PrintSql {
		dbConfig.Logger = logger.Default.LogMode(logger.Info) //开启sql打印
	}

	var dsn string
	if dataSourceInfo.Type == "mysql" {
		//dsn := "root:view@tcp(127.0.0.1:3306)/Dev_BricksBaseSystem?charset=utf8mb4&parseTime=True&loc=Local"
		//dsn := user + ":" + pass + "@tcp(" + ip + ":" + port + ")/" + dbName + "?charset=utf8mb4&serverTimezone=GMT%2B8&parseTime=True&loc=Local"
		dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", dataSourceInfo.User, dataSourceInfo.Pass, dataSourceInfo.Ip, dataSourceInfo.Port, dataSourceInfo.DbName)

	} else if dataSourceInfo.Type == "sqlite" {
		root := ""
		exePath, err := os.Executable()
		if err != nil {
			root = "."
		}

		root, _ = filepath.EvalSymlinks(filepath.Dir(exePath))

		dsn = dataSourceInfo.DbName
		if strings.HasPrefix(dsn, "./") {
			dsn = strings.Replace(dsn, "./", root+"/", 1)
			dsn = strings.Replace(dsn, "\\", "/", -1)
			dsn = strings.Replace(dsn, "//", "/", -1)
		}

		createFileDir(dsn)
	}

	db, err := gorm.Open(dbOpenFun(dsn), dbConfig)
	if err != nil {
		Log.Error("连接数据库错误:", err)
		return false, err.Error(), 1001
	}

	return true, "连接数据库成功", db
}

/**
 * 创建文件所在文件夹
 * 注意:必须是文件,否则只能创建出上级路径
 * @param filePath 文件路径
 * @return bool:是否成功(如果路径已经存在则不会创建,但返回true); error:错误信息
 */
func createFileDir(filePath string) (bool, error) {
	path := filepath.Dir(filePath) //获取上级目录
	_, err := os.Stat(path)        //os.Stat获取文件信息
	if err == nil {                //获取成功,说明文件存在
		return true, nil
	}

	if os.IsExist(err) { //再次判断路径是否存在,也可以使用os.IsNotExist(err)来判断是否不存在
		return true, nil
	}

	err = os.MkdirAll(path, os.ModePerm)
	if err != nil {
		return false, err
	}

	return true, nil
}
